import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter_baselib/flutter_baselib.dart';
import 'package:flutter_baselib_example/common/net/http_const.dart';
import 'package:flutter_baselib_example/common/net/http_urls.dart';
import 'package:flutter_baselib_example/common/net/interceptors/header_interceptor.dart';
import 'package:flutter_baselib_example/common/net/util/http_json_utils.dart';
import 'package:flutter_baselib_example/common/util/one_context_utils.dart';
import 'package:flutter_nativedialog_plugin/loadingdialog_plugin.dart';

///@date:  2021/2/26 14:01
///@author:  lixu
///@description: 全局http相关配置
///当前配置在[XApi]类中被调用
class HttpConfigImpl implements IHttpConfig {
  String _tag = 'HttpConfigImpl';

  ///配置默认值：http是否显示加载dialog
  @override
  bool isShowLoading() {
    return true;
  }

  ///配置默认值：http加载提示文本
  @override
  String configLoadingText() {
    return 'loading...';
  }

  ///配置默认值：加载中能否通过关闭加载弹窗取消请求
  @override
  bool isCancelableDialog() {
    return false;
  }

  ///配置默认值：请求失败时是否自动显示toast提示错误
  @override
  bool isShowFailToast() {
    return true;
  }

  ///配置默认值：请求前是否校验网络连接
  ///true：如果无网络，直接返回错误
  @override
  bool isCheckNetwork() {
    return true;
  }

  ///配置通用的http请求选项[BaseOptions]
  ///优先级最低，优先取[XApi]#[request]方法中配置的method和option
  @override
  BaseOptions configBaseOptions() {
    BaseOptions options = BaseOptions(
      baseUrl: HttpUrls.httpHost,
      connectTimeout: HttpConst.httpTimeOut,
      receiveTimeout: HttpConst.httpTimeOut,
      sendTimeout: HttpConst.httpTimeOut,
      contentType: XApi.contentTypeJson,
      method: XApi.methodPost,
      responseType: ResponseType.json,
    );
    return options;
  }

  ///返回http成功的响应码：部分应用可能有多个响应码表示请求成功
  @override
  List<String> configHttpResultSuccessCodeList() {
    List<String> codeList = [];
    codeList.add(HttpConst.httpResultSuccess.toString());
    codeList.add(HttpConst.juheHttpResultSuccess.toString());
    return codeList;
  }

  ///配置https
  @override
  bool configHttps(X509Certificate cert, String host, int port) {
    ///TODO 根据业务做校验

    ///true：忽略证书校验
    return true;
  }

  ///添加拦截器
  ///拦截器队列的执行顺序是FIFO，先添加的拦截器先执行
  @override
  List<Interceptor>? configInterceptors() {
    List<Interceptor> interceptors = [];

    ///添加http通用参数和请求头拦截器
    interceptors.add(HeaderInterceptor());

    ///TODO 可以添加拦截器实现http缓存逻辑，或其它功能
    return interceptors;
  }

  ///是否自动添加[LogInterceptors]默认日志拦截器,打印http请求响应相关的日志
  @override
  bool configLogEnable() {
    return true;
  }

  ///每个http请求前回调该方法获取baseUrl
  ///优先级高于[IHttpConfig]#[configBaseOptions]方法配置的baseUrl
  ///[url] 当前正在请求的接口url
  ///return: 返回null使用[IHttpConfig]#[configBaseOptions]方法配置的baseUrl
  @override
  Future<String?> getBaseUrl(String url) async {
    return HttpUrls.httpHost;
  }

  ///http请求失败时会回调该方法，判断token是否失效
  ///[errorBean] 请求失败对象
  @override
  Future<bool> isHttpRespTokenError(HttpErrorBean errorBean) async {
    return HttpConst.sysTokenError.toString() == errorBean.code || HttpConst.sysTokenExpired.toString() == errorBean.code;
  }

  ///http请求失败时，回调该方法统一显示错误的Toast提示
  ///业务层在该方法中，根据自己的需求显示Toast
  ///[errorBean] 请求失败对象
  @override
  Future<void> showFailToast(HttpErrorBean errorBean) async {
    ToastUtils.show(errorBean.toString(), isShowLong: true);
  }

  ///token失效时回调该方法
  ///[errorBean] 请求失败对象
  @override
  Future<void> onTokenErrorCallback(HttpErrorBean errorBean) async {
    ToastUtils.show("Token 失效：${errorBean.toString()}", isShowLong: true);

    ///TODO 实现token失效的业务逻辑
  }

  ///获取毫秒时间戳
  static int currentTimeMillis() {
    return new DateTime.now().millisecondsSinceEpoch;
  }

  ///将http响应的json解析成对象
  ///[url] 当前请求url
  ///[jsonData] http响应完整json
  ///[isRespListData] 响应数据是否是List格式
  @override
  Future<HttpResultBean<T>> parseJsonToObject<T>(String url, Map<String, dynamic> jsonData, bool isRespListData) async {
    ///TODO 参考下面代码逻辑，根据业务修改代码解析json为object
    int s = currentTimeMillis();
    HttpResultBean<T> bean = await HttpJsonUtils.parseJsonToObject<T>(url, jsonData, isRespListData);
    int e = currentTimeMillis();
    LogUtils.e(_tag, '解析json：$url，耗时：${e - s}ms');
    return bean;
  }

  //TODO 是否使用native loading Dialog,否则就是用flutter loading dialog显示
  bool isUseNativeLoadingDialog = true;

  ///http请求显示加载框：[XApi]#[request]方法isShowLoading字段为true时，会回调该方法
  ///[url] 当前请求url
  ///[tag] 当前请求对应的tag，唯一
  ///[cancelToken] 用于加载框关闭时取消http请求
  ///[loadingText] 加载提示提示
  ///[isCancelableDialog] 请求过程中能否关闭加载框,默认false
  @override
  void showLoading(String url, int tag, CancelToken cancelToken, String loadingText, bool isCancelableDialog) {
    LogUtils.i(_tag, 'showLoading tag:$tag  loadingText:$loadingText  isCancelableDialog:$isCancelableDialog');

    ///显示http加载dialog：isShowLoading为true时，会回调该方法
    if (isUseNativeLoadingDialog) {
      LoadingDialogPlugin.showHttpLoading(
        tag.toString(),
        canCancel: isCancelableDialog,
        onCancelListener: (_) {
          ToastUtils.show('关闭Native弹窗，取消请求');
          XApi().cancel(cancelToken);
        },
      );
    } else {
      OneContextUtils.oneContext.showDialog(
        barrierDismissible: false,
        barrierColor: Colors.transparent,
        isBackButtonDismissible: isCancelableDialog,
        builder: (_) {
          ///TODO 可以参考HttpLoadingDialog类自定义dialog样式
          return HttpLoadingDialog(loadingText);
        },
        onClickBackButtonDismissCallback: () {
          ///请求过程中关闭加载框时取消请求
          if (isCancelableDialog) {
            ToastUtils.show('关闭弹窗，取消请求');
            XApi().cancel(cancelToken);
          }
        },
      );
    }
  }

  ///http请求完成，关闭加载框：[XApi]#[request]方法isShowLoading字段为true时，会回调该方法
  ///[url] 当前请求url
  ///[tag]当前请求对应的tag，唯一
  ///[isCancelled]当前请求是否已经取消，如果已经取消则不用关闭dialog
  @override
  void hideLoading(String url, int tag, bool isCancelled) {
    LogUtils.i(_tag, 'hideLoading tag:$tag  isCancelled:$isCancelled');
    if (isUseNativeLoadingDialog) {
      LoadingDialogPlugin.hideHttpLoading(tag.toString());
    } else {
      if (!isCancelled && OneContextUtils.oneContext.hasDialogVisible) {
        OneContextUtils.oneContext.popDialog();
      }
    }
  }
}
